﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MCWorldLibrary
{
    class ChunkSection
    {
        private Chunk chunk;
        private int index;
        private NBT.CompoundTagPayload sectionTag;
        byte[] blocks;
        byte[] data;

        internal NBT.CompoundTagPayload SectionTag
        {
            get { return this.sectionTag; }
        }

        public ChunkSection(Chunk chunk, NBT.CompoundTagPayload data, int index)
        {
            this.chunk = chunk;
            this.sectionTag = data;
            this.index = index;

            if(this.sectionTag == null)
                CreateNewTag();

            this.blocks = (this.sectionTag.Value.Single(tag => tag.Name == "Blocks").Payload as NBT.ByteArrayPayload).Value;
            this.data = (this.sectionTag.Value.Single(tag => tag.Name == "Data").Payload as NBT.ByteArrayPayload).Value;
        }

        public byte GetBlock(int x, int y, int z)
        {
            return this.blocks[(y * 16 * 16) + (z * 16) + x];
        }

        public void SetBlock(int x, int y, int z, byte block)
        {
            this.blocks[(y * 16 * 16) + (z * 16) + x] = block;
        }

        public void SetBlocks(BlockData[, ,] blocks, Vector3 blockStart, Vector3 blockEnd, Vector3 chunkWorldCoordinate, bool airOverwrites)
        {
            for (int x = blockStart.X; x < blockEnd.X; x++)
            {
                for (int y = blockStart.Y; y < blockEnd.Y; y++)
                {
                    for (int z = blockStart.Z; z < blockEnd.Z; z++)
                    {
                        BlockData block = blocks[x, (this.index * 16) + (y - chunkWorldCoordinate.Y), z];
                        if (airOverwrites || block.BlockType != 0)
                        {
                            int index = (y * 16 * 16) + ((z - chunkWorldCoordinate.Z) * 16) + (x - chunkWorldCoordinate.X);

                            this.blocks[index] = block.BlockType;

                            if (index % 2 == 0)
                                this.data[index / 2] |= (byte)(block.DataValue & 0x0F);
                            else
                                this.data[index / 2] |= (byte)(block.DataValue << 4);

                            this.chunk.Heightmap.TrySet((x - chunkWorldCoordinate.X), (this.index * 16) + (y - chunkWorldCoordinate.Y), z - chunkWorldCoordinate.Z);
                        }
                    }
                }
            }
        }

        private void CreateNewTag()
        {
            this.sectionTag = new NBT.CompoundTagPayload(new List<NBT.Tag>()
            {
                new NBT.Tag() { Name = "Y", Type = NBT.TagType.Byte, Payload = new NBT.BytePayload((byte)index) },
                new NBT.Tag() { Name = "Blocks", Type = NBT.TagType.ByteArray, Payload = new NBT.ByteArrayPayload(new byte[4096]) },
                new NBT.Tag() { Name = "Data", Type = NBT.TagType.ByteArray, Payload = new NBT.ByteArrayPayload(new byte[2048]) },
                new NBT.Tag() { Name = "BlockLight", Type = NBT.TagType.ByteArray, Payload = new NBT.ByteArrayPayload(new byte[2048]) },
                new NBT.Tag() { Name = "SkyLight", Type = NBT.TagType.ByteArray, Payload = new NBT.ByteArrayPayload(new byte[2048]) }
            });
        }
    }
}
